"""
Enrollment Manager Module

Responsible for managing all student enrollment related operations, including:
- Student course enrollment and withdrawal
- Enrollment restriction checks
- Enrollment data persistence
"""

from typing import Dict, List, Optional, Any
from datetime import datetime
import json
import os
from pathlib import Path

# Add project root directory to Python path
import sys
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

from models.enrollment import Enrollment
from models.course import Course
from models.user import User, Student


class EnrollmentManager:
    """Enrollment Manager - Uses singleton pattern"""
    
    _instance = None
    
    def __new__(cls):
        """Singleton pattern implementation"""
        if cls._instance is None:
            cls._instance = super(EnrollmentManager, cls).__new__(cls)
            cls._instance._initialized = False
        return cls._instance
    
    def __init__(self):
        """Initialize enrollment manager"""
        if self._initialized:
            return
        
        self.enrollments: Dict[str, Enrollment] = {}  # enrollment_id -> Enrollment object
        self.student_enrollments: Dict[str, List[str]] = {}  # student_id -> [enrollment_ids]
        self.course_enrollments: Dict[str, List[str]] = {}  # course_id -> [enrollment_ids]
        self.data_file = os.path.join(project_root, "data", "enrollments.json")
        self._initialized = True
        self.load_enrollments()
    
    @classmethod
    def get_instance(cls):
        """Get EnrollmentManager singleton instance"""
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance
    
    def create_enrollment(self, student_id: str, course_id: str) -> Optional[Enrollment]:
        """
        Create enrollment record
        
        Parameters:
            student_id: Student ID
            course_id: Course ID
            
        Returns:
            Created enrollment object, returns None if failed
        """
        try:
            # Check if course manager is available
            from managers.course_manager import CourseManager
            course_manager = CourseManager.get_instance()
            course = course_manager.get_course(course_id)
            
            if not course:
                print(f"Error: Course {course_id} does not exist")
                return None
                
            # Check if student is already in course
            if student_id in course.student_ids:
                print(f"Student {student_id} is already in course {course_id}")
                return None
                
            # Check if course is full
            if course.is_full():
                print(f"Course {course_id} is full")
                return None
            
            # Generate enrollment ID
            enrollment_id = f"enrollment_{len(self.enrollments) + 1:06d}"
            
            # Create enrollment object
            enrollment = Enrollment(
                enrollment_id=enrollment_id,
                student_id=student_id,
                course_id=course_id
            )
            
            # Add to manager
            self.enrollments[enrollment_id] = enrollment
            
            # Update student enrollment index
            if student_id not in self.student_enrollments:
                self.student_enrollments[student_id] = []
            self.student_enrollments[student_id].append(enrollment_id)
            
            # Update course enrollment index
            if course_id not in self.course_enrollments:
                self.course_enrollments[course_id] = []
            self.course_enrollments[course_id].append(enrollment_id)
            
            # Add student to course
            if course.add_student(student_id):
                print(f"Successfully created enrollment record: Student {student_id} enrolled in course {course_id}")
                return enrollment
            else:
                # If adding student fails, rollback enrollment record
                del self.enrollments[enrollment_id]
                self.student_enrollments[student_id].remove(enrollment_id)
                self.course_enrollments[course_id].remove(enrollment_id)
                print(f"Failed to add student to course")
                return None
            
        except Exception as e:
            print(f"Error creating enrollment record: {e}")
            return None
    
    def get_enrollment(self, enrollment_id: str) -> Optional[Enrollment]:
        """
        Get enrollment record by enrollment ID
        
        Parameters:
            enrollment_id: Enrollment ID
            
        Returns:
            Enrollment object, returns None if not found
        """
        return self.enrollments.get(enrollment_id)
    
    def get_student_enrollments(self, student_id: str) -> List[Enrollment]:
        """
        Get all enrollment records for a student
        
        Parameters:
            student_id: Student ID
            
        Returns:
            List of enrollment objects
        """
        enrollment_ids = self.student_enrollments.get(student_id, [])
        return [self.enrollments[eid] for eid in enrollment_ids if eid in self.enrollments]
    
    def get_student_courses(self, student_id: str) -> List[Course]:
        """
        Get all courses that a student is enrolled in
        
        Parameters:
            student_id: Student ID
            
        Returns:
            List of course objects
        """
        from managers.course_manager import CourseManager
        course_manager = CourseManager.get_instance()
        
        enrollments = self.get_student_enrollments(student_id)
        courses = []
        
        for enrollment in enrollments:
            if enrollment.status == "active":
                course = course_manager.get_course(enrollment.course_id)
                if course:
                    courses.append(course)
        
        return courses
    
    def get_course_enrollments(self, course_id: str) -> List[Enrollment]:
        """
        Get all enrollment records for a course
        
        Parameters:
            course_id: Course ID
            
        Returns:
            List of enrollment objects
        """
        enrollment_ids = self.course_enrollments.get(course_id, [])
        return [self.enrollments[eid] for eid in enrollment_ids if eid in self.enrollments]
    
    def is_student_enrolled(self, student_id: str, course_id: str) -> bool:
        """
        Check if student is enrolled in course
        
        Parameters:
            student_id: Student ID
            course_id: Course ID
            
        Returns:
            Whether enrolled
        """
        student_enrollments = self.get_student_enrollments(student_id)
        for enrollment in student_enrollments:
            if enrollment.course_id == course_id and enrollment.status == "active":
                return True
        return False
    
    def update_enrollment_status(self, enrollment_id: str, status: str) -> bool:
        """
        Update enrollment status
        
        Parameters:
            enrollment_id: Enrollment ID
            status: New status (active, dropped, completed)
            
        Returns:
            Whether update was successful
        """
        enrollment = self.get_enrollment(enrollment_id)
        if not enrollment:
            print(f"Error: Enrollment record '{enrollment_id}' does not exist")
            return False
        
        try:
            # If status changes from active to dropped, need to remove student from course
            if enrollment.status == "active" and status == "dropped":
                from managers.course_manager import CourseManager
                course_manager = CourseManager.get_instance()
                course = course_manager.get_course(enrollment.course_id)
                if course:
                    course.remove_student(enrollment.student_id)
                    print(f"Removed student {enrollment.student_id} from course {enrollment.course_id}")
            
            enrollment.status = status
            enrollment.updated_at = datetime.now()
            print(f"Successfully updated enrollment status: {enrollment_id} -> {status}")
            return True
            
        except Exception as e:
            print(f"Error updating enrollment status: {e}")
            return False
    
    def drop_enrollment(self, enrollment_id: str) -> bool:
        """
        Drop enrollment (set enrollment status to dropped)
        
        Parameters:
            enrollment_id: Enrollment ID
            
        Returns:
            Whether drop was successful
        """
        return self.update_enrollment_status(enrollment_id, "dropped")
    
    def complete_enrollment(self, enrollment_id: str) -> bool:
        """
        Complete enrollment (set enrollment status to completed)
        
        Parameters:
            enrollment_id: Enrollment ID
            
        Returns:
            Whether completion was successful
        """
        return self.update_enrollment_status(enrollment_id, "completed")
    
    def rebuild_indexes(self) -> None:
        """
        Rebuild enrollment indexes
        Reconstruct student_enrollments and course_enrollments indexes from main enrollments dictionary
        """
        try:
            # Clear existing indexes
            self.student_enrollments.clear()
            self.course_enrollments.clear()
            
            # Rebuild indexes
            for enrollment_id, enrollment in self.enrollments.items():
                student_id = enrollment.student_id
                course_id = enrollment.course_id
                
                # Update student enrollment index
                if student_id not in self.student_enrollments:
                    self.student_enrollments[student_id] = []
                self.student_enrollments[student_id].append(enrollment_id)
                
                # Update course enrollment index
                if course_id not in self.course_enrollments:
                    self.course_enrollments[course_id] = []
                self.course_enrollments[course_id].append(enrollment_id)
            
            print(f"Enrollment index rebuild completed: {len(self.enrollments)} enrollment records")
            print(f"Student index: {len(self.student_enrollments)} students")
            print(f"Course index: {len(self.course_enrollments)} courses")
            
        except Exception as e:
            print(f"Error rebuilding enrollment indexes: {e}")

    def get_enrollment_statistics(self, course_id: str) -> Dict[str, Any]:
        """
        Get enrollment statistics for a course
        
        Parameters:
            course_id: Course ID
            
        Returns:
            Statistics dictionary
        """
        enrollments = self.get_course_enrollments(course_id)
        
        active_count = 0
        dropped_count = 0
        completed_count = 0
        
        for enrollment in enrollments:
            if enrollment.status == "active":
                active_count += 1
            elif enrollment.status == "dropped":
                dropped_count += 1
            elif enrollment.status == "completed":
                completed_count += 1
        
        return {
            "total_enrollments": len(enrollments),
            "active_enrollments": active_count,
            "dropped_enrollments": dropped_count,
            "completed_enrollments": completed_count,
            "course_id": course_id
        }
    
    def save_enrollments(self) -> bool:
        """
        Save enrollment data to file
        
        Returns:
            Whether save was successful
        """
        try:
            data = {}
            for enrollment_id, enrollment in self.enrollments.items():
                data[enrollment_id] = enrollment.to_dict()
            
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            
            return True
            
        except Exception as e:
            print(f"Error saving enrollment data: {e}")
            return False
    
    def load_enrollments(self) -> bool:
        """
        Load enrollment data from file
        
        Returns:
            Whether load was successful
        """
        try:
            if not os.path.exists(self.data_file):
                return True  # File not existing is normal
            
            with open(self.data_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
            
            self.enrollments = {}
            self.student_enrollments = {}
            self.course_enrollments = {}
            
            for enrollment_id, enrollment_data in data.items():
                enrollment = Enrollment.from_dict(enrollment_data)
                self.enrollments[enrollment_id] = enrollment
                
                # Rebuild indexes
                student_id = enrollment.student_id
                course_id = enrollment.course_id
                
                if student_id not in self.student_enrollments:
                    self.student_enrollments[student_id] = []
                self.student_enrollments[student_id].append(enrollment_id)
                
                if course_id not in self.course_enrollments:
                    self.course_enrollments[course_id] = []
                self.course_enrollments[course_id].append(enrollment_id)
            
            print(f"Successfully loaded {len(self.enrollments)} enrollment records")
            return True
            
        except Exception as e:
            print(f"Error loading enrollment data: {e}")
            return False
